#include "async_io.h"

#define BUFFER_SIZE 1024
const uint32_t DEF_EVENTS = EPOLLONESHOT | EPOLLRDHUP | EPOLLPRI | EPOLLERR | EPOLLHUP;

typedef struct Async_t
{
    uint32_t            events;         // 用于存储注册的事件类型
    uint32_t            fd;             // 文件描述符
    void               *buff_out;       // 异步写缓冲区
    void               *buff_in;        // 异步读缓冲区
    size_t              buff_out_size;  // 异步写缓冲区大小
    size_t              buff_in_size;   // 异步读缓冲区大小
    AsyncReadCallback   on_read;        // 异步读完成后的回调函数
    AsyncWriteCallback  on_out;         // 异步写完成后的回调函数
    AsyncCallback       on_err;         // 异步错误回调函数
    AsyncAcceptCallback on_accept;      // 异步连接接受完成后的回调函数
    AsyncCallback       on_rdhup;       // 异步连接读半部分关闭回调函数
    AsyncCallback       on_hup;         // 异步连接关闭回调函数
} Async_t;

#define ASYNC_SIZE sizeof(Async_t)

static int      epoll_fd = -1;
static bool     is_run   = false;
static Async_t *asyncs[BUFFER_SIZE];

static Async_t *get_self(int fd);
static int async_del(int fd);

// 从 epoll 实例中删除文件描述符
static int epoll_del(int fd)
{
    int statu = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
    if (statu == -1) {
        // 用户通常会在此之前 调用 close 函数关闭此 文件，忽略 EBADF 错误
        if (errno != EBADF)
            perror("epoll_del.epoll_ctl");
    }
    return statu;
}

// 添加文件描述符到 epoll 实例
static int epoll_add(Async_t *self)
{
    struct epoll_event _event;
    _event.data.ptr = self;
    _event.events   = self->events;
    int statu       = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, self->fd, &_event);
    if (statu == -1) {
        if (errno == EBADF)
            async_del(self->fd);
        perror("epoll_add.epoll_ctl");
    }
    return statu;
}

// 修改已注册文件描述符的事件类型和回调函数
static int epoll_mod(Async_t *self)
{
    struct epoll_event _event;
    _event.data.ptr = self;
    _event.events   = self->events;

    int statu = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, self->fd, &_event);
    if (statu == -1) {
        if (errno == EBADF)
            async_del(self->fd);
        perror("epoll_mod.epoll_ctl");
    }
    return statu;
}

// 从异步 I/O 对象数组中删除指定文件描述符对应的对象
static int async_del(int fd)
{
    // getself会创建对象，我们这里直接用下标访问
    Async_t *self = asyncs[fd];
    if (self) {
        epoll_del(fd);
        free(self);
        asyncs[fd] = NULL;
    }
    return 0;
}

// 处理 EPOLLIN 事件
static int do_in(Async_t *self)
{
    self->events &= ~EPOLLIN;  // 取消监听读事件，只触发一次
    epoll_mod(self);

    size_t read_size = 0;
    if (self->on_accept) {
        struct sockaddr_in client_addr;
        socklen_t          client_len;

        // 有新的连接
        client_len  = sizeof(client_addr);
        int conn_fd = accept(self->fd, (struct sockaddr *)&client_addr, &client_len);
        if (conn_fd == -1) {
            perror("accept");
            exit(1);
        }
        return self->on_accept(conn_fd, client_addr);
    }

    if (self->buff_in) {
        read_size =
            read(self->fd, self->buff_in, self->buff_in_size);
    }

    if (self->on_read) {
        void *p = self->buff_in;

        self->buff_in      = NULL;
        self->buff_in_size = 0;

        return self->on_read(self->fd, read_size, p);
    }
    return 0;
}

// 处理 EPOLLOUT 事件
static int do_out(Async_t *self)
{
    self->events &= ~EPOLLOUT;  // 取消监听写事件，只触发一次
    epoll_mod(self);
    size_t send_size = 0;
    if (self->buff_out) {
        while (send_size < self->buff_out_size) {
            size_t size = write(self->fd, self->buff_out + send_size, self->buff_out_size - send_size);
            send_size += size;
        }
        free(self->buff_out);
        self->buff_out      = NULL;
        self->buff_out_size = 0;
    }

    if (self->on_out) {
        AsyncWriteCallback callback = self->on_out;
        self->on_out                = NULL;

        return callback(self->fd, send_size);
    }
    return 0;
}

// 处理 EPOLLERR 事件
static int do_err(Async_t *self, uint32_t events)
{
    perror("EPOLLERR");

    if (self->on_err) {
        self->on_err(self->fd, events);
    }
    return -1;
}

static bool only_one_event(Async_t *self,uint32_t event){
    // 获取除默认事件外用户注册的其他事件
    uint32_t events = self->events & ~ DEF_EVENTS;
    // 判断是否只有 event 事件
    return events == event;
}

// 处理 EPOLLRDHUP 事件
static int do_rdhup(Async_t *self, uint32_t events)
{
    puts("EPOLLRDHUP");

    if (self->on_rdhup) {
        return self->on_rdhup(self->fd, events);
    }
    // 如果只监听 可读事件，但此时可读端已关闭，则可是删除此事件的监听
    else if (only_one_event(self, EPOLLIN)) {
        return -1;
    }
    return 0;
}
// 处理 EPOLLHUP 事件
static int do_hup(Async_t *self, uint32_t events)
{
    puts("EPOLLHUP");

    if (self->on_hup) {
        return self->on_hup(self->fd, events);
    }
    return -1;
}

/************************************* public ********************************************/
/************************************* public ********************************************/
/************************************* public ********************************************/

/// @brief 初始化异步 I/O 环境
/// @param
/// @return 成功：0 失败：-1
int async_init(void)
{
    // 创建 epoll 实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("epoll_create1");
        return -1;
    }
    is_run = true;
    return 0;
}

/// @brief 销毁异步 I/O 环境，释放资源
/// @param
/// @return  成功：0 失败：-1
int async_exit(void)
{
    is_run = false;
    return 0;
}

// 获取 Async_t 结构体，如果不存在则创建新的
static Async_t *get_self(int fd)
{
    Async_t *self = asyncs[fd];
    if (self == NULL) {
        self = malloc(ASYNC_SIZE);
        if (self == NULL) {
            return NULL;
        }

        memset(self, 0, ASYNC_SIZE);
        self->fd     = fd;
        self->events = EPOLLONESHOT | EPOLLRDHUP | EPOLLPRI | EPOLLERR | EPOLLHUP;
        if (epoll_add(self) == -1) {
            free(self);
            return NULL;
        }
        asyncs[fd] = self;
    }
    return self;
}

/// @brief 异步读取数据函数，读取完成后调用回调函数
/// @param fd 文件描述符
/// @param buff 存储读取数据的缓冲区指针
/// @param buff_size 缓冲区大小
/// @param callback 读取完成后的回调函数指针
/// @return  成功：0 失败：-1
int async_read(int fd, void *buff, size_t buff_size, AsyncReadCallback callback)
{
    Async_t *self = get_self(fd);
    if (self == NULL)
        return -1;
    self->buff_in      = buff;
    self->buff_in_size = buff_size;
    self->events |= EPOLLIN;
    self->on_read = callback;
    return epoll_mod(self);
}

/// @brief 异步写入数据函数，写入完成后调用回调函数
/// @param fd 文件描述符，用于标识要写入数据的文件
/// @param data 要写入的数据指针，指向要写入文件的数据缓冲区
/// @param data_size 数据大小，表示要写入的数据的字节数
/// @param callback 写入完成后的回调函数指针，用于在写入完成后执行自定义的回调操作
/// @return 成功：0 失败：-1
int async_write(int fd, const void *data, size_t data_size, AsyncWriteCallback callback)
{
    Async_t *self = get_self(fd);  // 获取与文件描述符相关的异步处理结构体
    if (self == NULL)
        return -1;

    if (data == NULL) {
        // 如果传入的数据指针为空，表示不需要写入数据，只注册回调函数
        // 在回调函数中可以进行其他自定义操作，比如通知写入完成等
        self->buff_out = malloc(self->buff_out_size + data_size);
        if (self->buff_out == NULL)
            return -1;
        memcpy(self->buff_out, data, data_size);
        self->buff_out_size = data_size;
    }
    else {
        // 如果传入的数据指针不为空，则将数据写入异步处理结构体的缓冲区中
        void *temp = malloc(self->buff_out_size + data_size);
        if (temp == NULL)
            return -1;
        memcpy(temp, self->buff_out, self->buff_out_size);
        memcpy(temp + self->buff_out_size, data, data_size);
        free(self->buff_out);
        self->buff_out      = temp;
        self->buff_out_size = self->buff_out_size + data_size;
    }

    // 设置监听写事件（EPOLLOUT），表示该文件描述符上可写入数据了
    self->events |= EPOLLOUT;

    // 设置写入完成后的回调函数
    self->on_out = callback;

    // 调用 epoll_mod 函数更新该文件描述符上的监听事件
    // epoll_mod 函数将根据设置的事件类型来更新 epoll 实例中的事件监听
    // 从而确保在文件描述符上可写入数据时触发回调函数
    return epoll_mod(self);
}

/// @brief 异步接受连接函数，接受连接后调用回调函数
/// @param fd 监听套接字
/// @param callback 连接接受完成后的回调函数指针
/// @return 成功：0 失败：-1
int async_accept(int fd, AsyncAcceptCallback callback)
{
    Async_t *self = get_self(fd);
    if (self == NULL)
        return -1;

    self->events |= EPOLLIN;
    self->on_accept = callback;
    return epoll_mod(self);
}

/// @brief 处理文件描述符上的 EPOLLERR 事件，当文件描述符发生错误时触发回调函数
/// @param fd 文件描述符
/// @param callback 错误处理的回调函数指针，用于在发生错误时执行自定义的错误处理操作
/// @return 成功：0 失败：-1
int async_error(int fd, AsyncCallback callback)
{
    Async_t *self = get_self(fd);
    if (self == NULL)
        return -1;

    self->events |= EPOLLERR;
    self->on_err = callback;
    return epoll_mod(self);
}

/// @brief 处理文件描述符上的 EPOLLRDHUP 事件，当 TCP 连接的读半部分关闭时触发回调函数
/// @param fd 文件描述符
/// @param callback 错误处理的回调函数指针，用于在发生错误时执行自定义的错误处理操作
/// @return 成功：0 失败：-1
int async_rdhup(int fd, AsyncCallback callback)
{
    Async_t *self = get_self(fd);
    if (self == NULL)
        return -1;

    self->events |= EPOLLRDHUP;
    self->on_rdhup = callback;
    return epoll_mod(self);
}

/// @brief 处理文件描述符上的 EPOLLHUP 事件，当文件描述符被挂起时触发回调函数
/// @param fd 文件描述符
/// @param callback 错误处理的回调函数指针，用于在发生错误时执行自定义的错误处理操作
/// @return 成功：0 失败：-1
int async_hup(int fd, AsyncCallback callback)
{
    Async_t *self = get_self(fd);
    if (self == NULL)
        return -1;

    self->events |= EPOLLHUP;
    self->on_hup = callback;
    return epoll_mod(self);
}

/**
 * 处理 epoll 事件
 * events: 用于标识发生的事件类型。它是一个32位无符号整数，可以使用以下宏定义来设置或检查事件类型：
 *      EPOLLIN: 表示对应的文件描述符可以读（包括 TCP 连接的读半部分关闭）。
 *      EPOLLOUT: 表示对应的文件描述符可以写。
 *      EPOLLRDHUP: 表示 TCP 连接的读半部分关闭。
 *      EPOLLPRI: 表示有紧急数据可读（这些数据会通过套接字的带外机制传输）。
 *      EPOLLERR: 表示对应的文件描述符发生错误。
 *      EPOLLHUP: 表示对应的文件描述符被挂起。
 *      EPOLLET: 表示以边缘触发方式工作（Edge-Triggered，非默认，仅适用于 epoll）。
 *      EPOLLONESHOT: 表示只监听一次事件（非默认，仅适用于 epoll）。
 * */
static void do_event(struct epoll_event *event)
{
    Async_t *self = event->data.ptr;

    int status = 0;
    if (event->events & EPOLLIN)
        status += do_in(self);

    if (event->events & EPOLLOUT)
        status += do_out(self);

    // if (event->events & EPOLLPRI)
    //     ;

    if (event->events & EPOLLERR)
        status += do_err(self, event->events);

    if (event->events & EPOLLRDHUP)
        status += do_rdhup(self, event->events);

    if (event->events & EPOLLHUP)
        status += do_hup(self, event->events);

    if (status < 0)
        async_del(self->fd);
}

/// @brief 异步事件循环函数，不断监听和处理异步 I/O 操作的完成
/// @return
int async_exec(void)
{
    struct epoll_event events[10];

    // 没有调用 async_init 无法运行
    if (!is_run)
        return -1;

    while (is_run) {
        int realy_num = epoll_wait(epoll_fd, events, 10, 1000);
        if (realy_num == -1) {
            perror("epoll_wait");
            return -1;
        }
        for (int i = 0; i < realy_num; i++) {
            do_event(&events[i]);
        }
    }

    // 销毁 epoll_fd
    close(epoll_fd);
    epoll_fd = -1;

    // 释放资源
    for (size_t i = 0; i < BUFFER_SIZE; i++) {
        if (asyncs[i]) {
            // 释放输出缓冲区的内存
            if (asyncs[i]->buff_out) {
                free(asyncs[i]->buff_out);
            }
            free(asyncs[i]);
            asyncs[i] = NULL;
        }
    }

    return 0;
}